#include"connectionpool.hpp"
#include"public.hpp"


//懒汉式单例模式
ConnectionPool* ConnectionPool::getConnectionPool() {
	static ConnectionPool pool;
	return &pool;
}

//连接池的构造
ConnectionPool::ConnectionPool(){	
	cout<<"create connectionPool"<<endl;
	//加载配置文件
	if (!loadConfigFile()) {
		return;
	}
	//创建初始连接
	for (int i = 0; i < _initSize; ++i) {
		Connection* p = new Connection();
		if(!p->connect(_ip, _port, _username, _password, _dbname)){
            cout<<"数据库连接失败"<<endl;
        }
        else{
            cout<<"数据库连接成功"<<endl;
        }
        
		p->refreshAliveTime();
		_connectionQue.push(p);
		_connectionCnt++;
	}

	//启动新线程，创建连接,
	//成员函数没法作为线程函数，需要使用绑定器，将当前对象地址绑定为第一个参数，才能作为线程函数调用
	thread produce(std::bind(&ConnectionPool::produceConnectionTask, this));
	produce.detach();

	//启动一个线程，扫描是否有连接超出空闲时间
	thread scanner(std::bind(&ConnectionPool::scannerConnectionTask, this));
	scanner.detach();
}

//扫描是否有连接超出空闲时间
void ConnectionPool::scannerConnectionTask() {
	for (;;) {
		//定时睡眠
		this_thread::sleep_for(chrono::seconds(_maxIdleTime));
		
		//扫描队列，释放连接
		unique_lock<mutex> lock(_queueMutex);
		while (_connectionCnt > _initSize) {
			Connection* p = _connectionQue.front();
			if (p->getAliveTime() >= (_maxIdleTime * 1000)) {
				_connectionQue.pop();
				_connectionCnt--;
				delete p; //调用~Connection()释放连接
			}
			else {
				break;//队头都没有超时，其他也没有超时
			}
		}
	}
}

//加载配置文件
bool ConnectionPool::loadConfigFile() {
	FILE* pf = fopen("/home/cjx/cppproject/chatServer/chat-server/src/server/mysql.ini", "r");
	if (pf == nullptr) {
		LOG("mysql.ini file is not exist");
		return false;
	}

	while (!feof(pf)) {
		char line[1024] = { 0 };
		fgets(line, 1024, pf);
		string str = line;
		int idx = str.find('=', 0);
		if (idx == -1) {//读到注释
			continue;
		}
		int endidx = str.find('\n', idx);
		string key = str.substr(0, idx);
		string value = str.substr(idx + 1, endidx - idx - 1);

		if (key == "ip")
		{
			_ip = value;
		}
		else if (key == "port")
		{
			_port = atoi(value.c_str());
		}
		else if (key == "username")
		{
			_username = value;
		}
		else if (key == "password")
		{
			_password = value;
		}
		else if (key == "dbname")
		{
			_dbname = value;
		}
		else if (key == "initSize")
		{
			_initSize = atoi(value.c_str());
		}
		else if (key == "maxSize")
		{
			_maxSize = atoi(value.c_str());
		}
		else if (key == "maxIdleTime")
		{
			_maxIdleTime = atoi(value.c_str());
		}
		else if (key == "connectionTimeOut")
		{
			_connectionTimeout = atoi(value.c_str());
		}

	}
	return true;
}

//生成线程函数
void ConnectionPool::produceConnectionTask() {
	for (;;) {
		unique_lock<mutex> lock(_queueMutex);
		while (!_connectionQue.empty()) {
			cv.wait(lock);//队列不空，此处生产者进入等待
		}
		//连接数量没有到达上限，继续创建
		if (_connectionCnt < _maxSize) {
			Connection* p = new Connection();
			p->connect(_ip, _port, _username, _password, _dbname);
			p->refreshAliveTime();
			_connectionQue.push(p);
			_connectionCnt++;
		}
		//通知消费者线程，可以消费
		cv.notify_all();
	}
}

shared_ptr<Connection> ConnectionPool::getConnection() {

	unique_lock<mutex> lock(_queueMutex);
	while (_connectionQue.empty()) {
		if (cv_status::timeout == cv.wait_for(lock, chrono::milliseconds(_connectionTimeout))) {
			if (_connectionQue.empty()) {
				LOG("获取连接超时...");
				return nullptr;
			}
			
		}
	}

	cout<<"连接池非空"<<endl;
	/*
	自定义删除器，防止智能指针析构时，自动删除Connection
	*/
	shared_ptr<Connection> sp(_connectionQue.front(),
		[&](Connection* pcon) {
			unique_lock<mutex> lock(_queueMutex);
			pcon->refreshAliveTime();
			_connectionQue.push(pcon);
		});

	_connectionQue.pop();
	if (_connectionQue.empty()) {
		cv.notify_all();
	}
	return sp;
}
